#include "sm_wifi.h"
#include "sm_nvs.h"
#include "sm_console.h"


#include "esp_smartconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_event.h"
#include "esp_log.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include <string.h>
#include <stdlib.h>
#include <lwip/sockets.h>

#include "esp_ping.h"
#include "ping/ping.h"

#define WIFI_NVS_FLASH_INFO_NAME "WiFiInfo"
#define WIFI_NVS_FLASH_SSID_KEY "Ssid"
#define WIFI_NVS_FLASH_PAWD_KEY "Pawd"
#define EXAMPLE_ESP_MAXIMUM_RETRY   5
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

#define WIFI_SMARTCONFIG_FUNC_FLAG  0

#define SM_WIFI_TAG "sm wifi"

static char host_ip[32] = {0};
// static EventGroupHandle_t s_wifi_event_group;
// static TaskHandle_t _wait_wifi_connect_task_handle;

struct __event_instance_handle
{
	esp_event_handler_instance_t instance_any_id_handle;
	esp_event_handler_instance_t instance_got_ip_handle;
	esp_event_handler_instance_t instance_sc_event_handle;
};

struct __event_instance_handle _event_handle = {0};

struct __wifi_info
{
	uint8_t ssid[32];
	uint8_t password[64];
};

struct __wifi_info wifi_info = {0};



void client_connect_server_task(void *parm)
{
	// ESP_LOGI(TAG_UDP,"true on udp service task");

	int non_blocking = 1;

	struct sockaddr_in udp_addr = {0};
	// struct Udp_socket_fd  = udp_service_start();
	int udp_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);

	udp_addr.sin_family = AF_INET;                           	// 设置地址族为IPv4
	udp_addr.sin_port = htons(12355);				// 设置地址的端口号信息
	udp_addr.sin_addr.s_addr = htonl(IPADDR_BROADCAST);	    	//　设置IP地址

	// if(bind(udp_socket_fd, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr_in)) != 0)
	// {
	// 	/*失败*/
	// 	close(udp_socket_fd);
	// 	ESP_LOGI(TAG_UDP,"udp bind fail: %d",udp_socket_fd);
	// }
	// else
	// {
	// 	/*成功*/
	// 	ESP_LOGI(TAG_UDP,"udp bind success: %d",udp_socket_fd);
	// }

	ioctlsocket(udp_socket_fd,FIONBIO,&non_blocking);//设置非阻塞


	for (;;)
	{

		sendto(udp_socket_fd,"hello\r\n",strlen("hello\r\n"),0,(struct sockaddr*)&udp_addr,sizeof(struct sockaddr_in));
		
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	
	}
}


inline static esp_err_t _get_nvs_flash_wifi_ssid_and_pawd(wifi_config_t *config)
{
	esp_err_t err = ESP_OK;
	err = sm_nvs_flash_read(WIFI_NVS_FLASH_INFO_NAME,WIFI_NVS_FLASH_SSID_KEY,(char*)config->sta.ssid,sizeof(config->sta.ssid));
	err |= sm_nvs_flash_read(WIFI_NVS_FLASH_INFO_NAME,WIFI_NVS_FLASH_PAWD_KEY,(char*)config->sta.password,sizeof(config->sta.password));

	return err;
}

inline static esp_err_t _set_nvs_flash_wifi_ssid_and_pawd(wifi_config_t *config)
{
	esp_err_t err = ESP_OK;
	err = sm_nvs_flash_write(WIFI_NVS_FLASH_INFO_NAME,WIFI_NVS_FLASH_SSID_KEY,(char*)config->sta.ssid);
	err |= sm_nvs_flash_write(WIFI_NVS_FLASH_INFO_NAME,WIFI_NVS_FLASH_PAWD_KEY,(char*)config->sta.password);
	return err;
}

static void _wifi_event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
	static uint8_t s_retry_num = 0;

	if(event_base == WIFI_EVENT)
	{
		switch (event_id)
		{
			default:
			break;

			case WIFI_EVENT_STA_START:
			{
				ESP_LOGI(SM_WIFI_TAG,"begin connect");
				esp_wifi_connect();
				break;
			}
				

			case WIFI_EVENT_STA_DISCONNECTED:
			{
				if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
				{
					esp_wifi_connect();
					s_retry_num++;
					ESP_LOGI(SM_WIFI_TAG, "retry to connect to the AP : %d",s_retry_num);
				}
				else
				{
					s_retry_num = 0;
					ESP_LOGI(SM_WIFI_TAG, "failed to connect to ap");
					#if WIFI_SMARTCONFIG_FUNC_FLAG == 1
						ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH));
						smartconfig_start_config_t smartconfig_cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
						ESP_ERROR_CHECK(esp_smartconfig_start(&smartconfig_cfg));

					#endif
				}
			}
			break;

			case WIFI_EVENT_STA_CONNECTED:
			{
				s_retry_num = 0;
			}
		}
	}

}

#if WIFI_SMARTCONFIG_FUNC_FLAG == 1

static void _smartconfig_event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
	if(event_base == SC_EVENT)
	{
		switch (event_id)
		{
			default:
				break;

			case SC_EVENT_SCAN_DONE:
				ESP_LOGI(SM_WIFI_TAG, "Scan done");
				break;
			
			case SC_EVENT_FOUND_CHANNEL:
			ESP_LOGI(SM_WIFI_TAG, "Found channel");
			break;

			case SC_EVENT_GOT_SSID_PSWD:
			{
				ESP_LOGI(SM_WIFI_TAG, "Got SSID and password");

				smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
				
				wifi_config_t wifi_config = {0};
				uint8_t ssid[33] = { 0 };
				uint8_t password[65] = { 0 };
				uint8_t rvd_data[33] = { 0 };

				memset(&wifi_config,0,sizeof(wifi_config_t));
				memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
				memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
				wifi_config.sta.bssid_set = evt->bssid_set;
				if (wifi_config.sta.bssid_set == true) 
				{
					memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
				}

				memcpy(ssid, evt->ssid, sizeof(evt->ssid));
				memcpy(password, evt->password, sizeof(evt->password));
				ESP_LOGI(SM_WIFI_TAG, "wifi name : %s", ssid);
				ESP_LOGI(SM_WIFI_TAG, "wifi passwd:%s", password);
				if (evt->type == SC_TYPE_ESPTOUCH_V2) 
				{
					ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
					ESP_LOGI(SM_WIFI_TAG, "RVD_DATA:");
					for (int i=0; i<33; i++) 
					{
						printf("%02x ", rvd_data[i]);
					}
					printf("\n");
				}

				ESP_ERROR_CHECK(esp_wifi_disconnect());
				ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
				esp_wifi_connect();
			}
			break;

			case SC_EVENT_SEND_ACK_DONE:
			{
				ESP_LOGI(SM_WIFI_TAG,"smartconfig done");
				xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
			}
			break;
		}
	}
}

#endif


static void _ip_event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
	if(event_base == IP_EVENT) 
	{
		switch(event_id)
		{
			case IP_EVENT_STA_GOT_IP:
			{
				ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
				strcpy(host_ip,ip4addr_ntoa((ip4_addr_t*)&event->ip_info.ip));
				ESP_LOGI(SM_WIFI_TAG, "got ip:%s",host_ip);

				wifi_config_t config = {0};
				strcpy((char*)config.sta.ssid,(char*)wifi_info.ssid);
				strcpy((char*)config.sta.password,(char*)wifi_info.password);
				_set_nvs_flash_wifi_ssid_and_pawd(&config); //保存至NVS FLASH

				ESP_LOGI(SM_WIFI_TAG,"ssid : %s",config.sta.ssid);
				ESP_LOGI(SM_WIFI_TAG,"password : %s",config.sta.password);

				ESP_LOGI(SM_WIFI_TAG, "connected to ap");

				// xTaskCreate((TaskFunction_t)client_connect_server_task,"client_connect_server_task",512*10,(void*)"192.168.137.1",4,NULL);

				ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MIN_MODEM));//省电模式

				
				ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, _event_handle.instance_any_id_handle));
				#if WIFI_SMARTCONFIG_FUNC_FLAG == 1
				ESP_ERROR_CHECK(esp_event_handler_instance_unregister(SC_EVENT, ESP_EVENT_ANY_ID, _event_handle.instance_sc_event_handle));
				#endif
				ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, _event_handle.instance_got_ip_handle));
				return;
			}
			break;
		}
	}
}

esp_err_t pingResults(ping_target_id_t msgType, esp_ping_found * pf)
{
    printf("AvgTime:%.1fmS Sent:%d Rec:%d min(mS):%d max(mS):%d Resp(mS):%d Timeouts:%d Total Time:%d\n", (float)pf->total_time/pf->recv_count, pf->send_count, pf->recv_count,  pf->min_time, pf->max_time ,pf->resp_time, pf->timeout_count, pf->total_time);
    return ESP_OK;
}







esp_err_t sm_wifi_connect_wifi(const char* ssid,const char* password)
{
	wifi_ap_record_t ap_config;
	if(esp_wifi_sta_get_ap_info(&ap_config) == ESP_OK)
	{
		ESP_ERROR_CHECK(esp_wifi_disconnect());

		ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &_wifi_event_handler,NULL,&_event_handle.instance_any_id_handle));
		ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &_ip_event_handler, NULL,&_event_handle.instance_got_ip_handle));
		#if WIFI_SMARTCONFIG_FUNC_FLAG == 1
		ESP_ERROR_CHECK(esp_event_handler_instance_register(SC_EVENT, ESP_EVENT_ANY_ID, &_smartconfig_event_handler,NULL, &_event_handle.instance_sc_event_handle));
		#endif
	}

	wifi_config_t config = {0};
	strcpy((char*)config.sta.ssid,ssid);
	strcpy((char*)config.sta.password,password);

	ESP_LOGI(SM_WIFI_TAG,"SSID : %s",(char*)config.sta.ssid);
	ESP_LOGI(SM_WIFI_TAG,"PASSWD : %s",(char*)config.sta.password);

	strcpy((char*)wifi_info.ssid,(char*)config.sta.ssid);
	strcpy((char*)wifi_info.password,(char*)config.sta.password);

	if(strlen(password))
	{
		config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
	}

	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &config));

	ESP_ERROR_CHECK(esp_wifi_connect());

	return ESP_OK;
}


int wifi_console_cb(int arge,char** argv)
{
	if(arge < 2)
		return -1;


	if(strcmp(argv[1],"connect") == 0)
	{
		sm_wifi_connect_wifi(argv[2],argv[3]);
	}

	else if(strcmp(argv[1],"clear") == 0)
	{
		ESP_ERROR_CHECK(sm_nvs_flash_erase_key(WIFI_NVS_FLASH_INFO_NAME,WIFI_NVS_FLASH_SSID_KEY));
		ESP_ERROR_CHECK(sm_nvs_flash_erase_key(WIFI_NVS_FLASH_INFO_NAME,WIFI_NVS_FLASH_PAWD_KEY));
	}
	return 0;
}



void sm_wifi_init(void)
{
	static esp_console_cmd_t wifi_console = 
	{
		.command = "wifi",
		.help = "crtl wifi func",
		.func = &wifi_console_cb
	};

	

	ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &_wifi_event_handler,NULL,&_event_handle.instance_any_id_handle));
	ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &_ip_event_handler, NULL,&_event_handle.instance_got_ip_handle));
	#if WIFI_SMARTCONFIG_FUNC_FLAG == 1
	ESP_ERROR_CHECK(esp_event_handler_instance_register(SC_EVENT, ESP_EVENT_ANY_ID, &_smartconfig_event_handler,NULL, &_event_handle.instance_sc_event_handle));
	#endif


	ESP_ERROR_CHECK(esp_netif_init());
	esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
	assert(sta_netif);

	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&cfg));

	wifi_config_t wifi_config = {0};

	if(_get_nvs_flash_wifi_ssid_and_pawd(&wifi_config) == ESP_OK)
	{
		if(strlen((char*)wifi_config.sta.password) > 0)
		{
			wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
		}
		strcpy((char*)wifi_info.ssid,(char*)wifi_config.sta.ssid);
		strcpy((char*)wifi_info.password,(char*)wifi_config.sta.password);
	}
	else
	{
		ESP_LOGW(SM_WIFI_TAG,"nvs flash no wifi ssid and passwd");
	}


	ESP_LOGI(SM_WIFI_TAG,"ssid : %s",wifi_config.sta.ssid);
	ESP_LOGI(SM_WIFI_TAG,"password : %s",wifi_config.sta.password);

	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));    //设置wifi模式为STA
	ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

	ESP_ERROR_CHECK(esp_wifi_start());

	sm_console_add_table(&wifi_console);
}
